﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Linq;

namespace BrokerBase.Lib.Client
{
    public class LicenseInfo
    {
        private static readonly string Lic_File_Name = "license.lic";
        private static readonly string Key2 = "xml@";
        private static readonly string Key3 = "ghml";

        private static readonly string mf = "9b%u";
        private const string kk = "7v(z";

        //private bool isEffective;
        private string description;

        //private string cpuSerialNo;
        //private string diskSerialNo;
        //private string macSerialNo;

        public static LicenseInfo GetInstance()
        {
            FileStream fs = null;

            LicenseInfo lic = new LicenseInfo();

            if (!File.Exists(Lic_File_Name))
            {
                LicenseInfo.CreateInstance();
            }

            try
            {

                fs = new FileStream(Lic_File_Name, FileMode.Open, FileAccess.Read);

                byte[] data = new byte[fs.Length];

                fs.Read(data, 0, data.Length);

                byte[] data2 = E2(data, mf, mf);

                string xml = Encoding.Unicode.GetString(data2);

                StringReader sr = new StringReader(xml);

                XElement element = XElement.Load(sr);

                lic.PresenterName = element.Element("PresenterName").Value;
                lic.UserName = element.Element("UserName").Value;
                lic.LicenseCode = element.Element("LicenseCode").Value;

                lic.DISKSerialNo = ClientTool.GetDiskId();
                lic.MACSerialNo = ClientTool.GetMacId();

                IEnumerable<XElement> regInfoEls = element.Elements("RegInfo");

                foreach (XElement el in regInfoEls)
                {
                    RegInfo reg = new RegInfo();

                    reg.LicInfo = lic;
                    reg.ActiveCode = el.Element("ActiveCode").Value;
                    reg.BeginTime = DateTime.Parse(el.Element("BeginTime").Value);
                    reg.EndTime = DateTime.Parse(el.Element("EndTime").Value);
                    reg.Period = int.Parse(el.Element("Period").Value);
                    reg.FingerprintOfDISK = el.Element("FingerprintOfDISK").Value;
                    reg.FingerprintOfMAC = el.Element("FingerprintOfMAC").Value;
                    reg.FingerprintOfMB = el.Element("FingerprintOfMB").Value;

                    reg.LicenseType = int.Parse(el.Element("LicenseType").Value);
                    lic.RegInfos.Add(reg);
                }
            }
            catch (Exception er)
            {
                throw er;
            }
            finally
            {
                fs.Close();
            }


            return lic;
        }

        /// <summary>
        /// 创建一个许可文件实例，并保存
        /// </summary>
        public static void CreateInstance()
        {
            LicenseInfo info = new LicenseInfo();
            //info.LicenseCode = Guid.NewGuid().ToString();

            Save(info);
        }

        public static void Save(LicenseInfo info)
        {
            try
            {
                string xml = GetXml(info);
                byte[] b1 = E1(Encoding.Unicode.GetBytes(xml), mf, mf);
                SaveData(b1);
            }
            catch (Exception er)
            {
                throw er;
            }
        }

        private static void SaveData(byte[] text)
        {
            FileStream fs = new FileStream(Lic_File_Name, FileMode.Create, FileAccess.Write);
            fs.Write(text, 0, text.Length);
            fs.Close();
        }

        private static string GetXml(LicenseInfo info)
        {
            XElement root = new XElement("Lic");

            XElement presenterName = new XElement("PresenterName", info.PresenterName);
            XElement userName = new XElement("UserName", info.UserName);
            XElement licenseCode = new XElement("LicenseCode", info.LicenseCode);

            root.Add(new XElement("PresenterName", info.PresenterName));
            root.Add(new XElement("UserName", info.UserName));
            root.Add(licenseCode = new XElement("LicenseCode", info.LicenseCode));


            foreach (RegInfo reg in info.RegInfos)
            {
                XElement code = new XElement("ActiveCode", reg.ActiveCode);
                XElement beginTime = new XElement("BeginTime", reg.BeginTime.ToString("yyyy-MM-dd"));
                XElement endTime = new XElement("EndTime", reg.EndTime.ToString("yyyy-MM-dd"));
                XElement period = new XElement("Period", reg.Period);
                XElement licType = new XElement("LicenseType", reg.LicenseType);
                //XElement current = new XElement("Current", reg.IsCurrent);
                XElement f1 = new XElement("FingerprintOfDISK", reg.FingerprintOfDISK);
                XElement f2 = new XElement("FingerprintOfMAC", reg.FingerprintOfMAC);
                XElement f3 = new XElement("FingerprintOfMB", reg.FingerprintOfMB);

                XElement regEl = new XElement("RegInfo", code, beginTime, endTime, period, licType, f1, f2, f3);

                root.Add(regEl);
            }

            XDocument doc = new XDocument(root);

            string s = doc.ToString();
            return s;

        }
        private static byte[] E1(byte[] text, string key, string iv)//加密
        {
            DESCryptoServiceProvider descsp = new DESCryptoServiceProvider();   //实例化加/解密类对象 
            descsp.Mode = CipherMode.CBC;
            byte[] bKey = Encoding.Unicode.GetBytes(key); //定义字节数组，用来存储密钥  
            byte[] bIv = Encoding.Unicode.GetBytes(iv);

            MemoryStream ms = new MemoryStream(); //实例化内存流对象
            CryptoStream cs = new CryptoStream(ms, descsp.CreateEncryptor(bKey, bIv), CryptoStreamMode.Write);
            cs.Write(text, 0, text.Length);  //向加密流中写入数据
            cs.FlushFinalBlock();

            return ms.ToArray();
            //return Convert.ToBase64String(ms.ToArray());
        }


        private static byte[] E2(byte[] text, string key, string iv)//解密
        {
            DESCryptoServiceProvider descsp = new DESCryptoServiceProvider();   //实例化加/解密类对象  
            descsp.Mode = CipherMode.CBC;

            byte[] bKey = Encoding.Unicode.GetBytes(key); //定义字节数组，用来存储密钥  
            byte[] bIv = Encoding.Unicode.GetBytes(iv);
            MemoryStream ms = new MemoryStream(); //实例化内存流对象    
            //使用内存流实例化解密流对象     
            CryptoStream cs = new CryptoStream(ms, descsp.CreateDecryptor(bKey, bIv), CryptoStreamMode.Write);
            cs.Write(text, 0, text.Length);      //向解密流中写入数据   
            cs.FlushFinalBlock();               //释放解密流    

            return ms.ToArray();
        }

        public static bool EF(LicenseInfo info)//验证数字指纹
        {
            bool success = false;
            DateTime currentTime = DateTime.Now;
            if (info != null)
            {
                foreach (RegInfo reg in info.RegInfos)
                {
                    if (currentTime <= reg.EndTime)
                    {
                        string tmp = "k" + info.UserName + "g" + reg.ActiveCode + "x" + reg.BeginTime.ToString("yyyy-MM-dd") + "y" + reg.EndTime.ToString("yyyy-MM-dd") + "z" + reg.Period + "f";

                        string tmp1 = tmp + ClientTool.GetDiskId();
                        string f1 = FS(tmp1);

                        string tmp2 = tmp + ClientTool.GetMacId();
                        string f2 = FS(tmp2);

                        if (reg.FingerprintOfDISK == f1 || reg.FingerprintOfMAC == f2)
                        {
                            success = true;
                            break;
                        }
                    }
                }
            }
            else
            {
                success = false;
            }

            return success;
        }

        public static string FS(string text)
        {
            MD5 m = new MD5CryptoServiceProvider();

            byte[] data = Encoding.Unicode.GetBytes(text);

            byte[] r = m.ComputeHash(data);
            string tmp = BitConverter.ToString(r);
            tmp = tmp.Replace("-", string.Empty);
            return tmp;
        }

        public static bool Verify(LicenseInfo info)
        {
            bool isVerfiy = EF(info);
            if (isVerfiy)
            {
                int v = (int)info.MaxEndTime.Value.Subtract(DateTime.Now).TotalDays;
                if (v > 0)
                {
                    info.description = "正式版";
                }
                else
                {
                    info.description = "软件许可已经过期";
                }
            }
            else
            {
                info.description = "软件许可证错误!";
            }

            return isVerfiy;
        }

        public static string CalcFingerprint(string userName, string code, DateTime? beginTime, DateTime? endTime, int period, string serialNo)
        {
            string tmp1 = "k" + userName + "g" + code + "x" + beginTime.Value.ToString("yyyy-MM-dd") + "y" + endTime.Value.ToString("yyyy-MM-dd") + "z" + period + "f" + serialNo;

            return FS(tmp1);
        }

        private LicenseInfo()
        {
            this.RegInfos = new List<RegInfo>();

        }
        /// <summary>
        /// 推荐人
        /// </summary>
        public string PresenterName { get; set; }
        /// <summary>
        /// 注册用户名
        /// </summary>
        public string UserName { get; set; }
        /// <summary>
        /// 授权许可号
        /// </summary>
        public string LicenseCode { get; set; }
        /// <summary>
        /// 硬盘序列号
        /// </summary>
        public string DISKSerialNo { get; set; }
        /// <summary>
        /// MAC地址
        /// </summary>
        public string MACSerialNo { get; set; }
        /// <summary>
        /// 主板地址
        /// </summary>
        public string MBSerialNo { get; set; }
        /// <summary>
        /// 激活码注册列表
        /// </summary>
        public IList<RegInfo> RegInfos { get; set; }
        /// <summary>
        /// 是否激活
        /// </summary>
        public bool IsEffective
        {
            get
            {
                return LicenseInfo.Verify(this);
            }
        }

        public int LastDay
        {
            get
            {
                int tmp = 0;

                if (MaxEndTime != null)
                    tmp = (int)MaxEndTime.Value.Subtract(DateTime.Now).TotalDays;
                else
                    tmp = 0;
                return tmp > 0 ? tmp : 0;
            }
        }

        public string Description
        {
            get
            {
                return description;
            }
        }

        public DateTime? MaxEndTime
        {
            get
            {
                if (RegInfos.Count > 0)
                    return RegInfos.Max(p => p.EndTime);
                else
                    return null;
            }
        }

        public int MaxLicenseType
        {
            get
            {
                if (RegInfos.Count > 0)
                    return RegInfos.Max(p => p.LicenseType);
                else
                    return 0;
            }
        }

        public RegInfo GetCurrentRegInfo()
        {
            DateTime c = DateTime.Now;
            RegInfo r = this.RegInfos.Where(p => c >= p.BeginTime && c <= p.EndTime && p.LicenseType == RegInfos.Max(q => q.LicenseType)).FirstOrDefault();

            return r;
        }

        public RegistrantInfo CreateRegistrantInfo()
        {
            RegistrantInfo info = new RegistrantInfo();
            info.UserName = this.UserName;
            info.PresenterName = PresenterName;
            info.LicenseCode = LicenseCode;

            return info;
        }

        private XElement GetClientInfoXml(RegInfo regInfo)
        {
            string diskId = ClientTool.GetDiskId();
            string macId = ClientTool.GetMacId();

            XElement root = new XElement("clientInfo");
            XElement userName = new XElement("UserName", regInfo.LicInfo.UserName);
            XElement presenterName = new XElement("PresenterName", regInfo.LicInfo.PresenterName);
            XElement licenseCode = new XElement("LicenseCode", regInfo.LicInfo.LicenseCode);
            XElement activeCode = new XElement("ActiveCode", regInfo.ActiveCode);
            XElement diskNo = new XElement("DiskNo", diskId);
            XElement macNo = new XElement("MacNo", macId);

            root.Add(userName, presenterName, licenseCode, activeCode, diskNo, macNo);

            return root;
        }
    }
}
